//
//  LBReactSinglePatcher.m
//  LBReactSinglePatcher
//
//  Created by WuShiHai on 19/5/24.
//  Copyright (c) 2019 Lebbay All rights reserved.
//

#import "LBReactSinglePatcher.h"

#import <LBFoundation/LBFoundation.h>
#import <LBUIKit/LBUIKit.h>
#import <LBNetworking/LBNetworking.h>
#import <LBNetworking/LBAPP.h>

//#import <LBEncrypt/LBAES.h>
#import "LBReactPatcherModel.h"
#import "LBDatabase.h"
#import "LBReactPatcherResponseModel.h"
#import "LBReactPatcherDao.h"
#import "LBReactPatcherConfigurationHeader.h"

@interface LBReactSinglePatcher()

@property (nonatomic, strong) NSDictionary *launchOptions;

@property (nonatomic, assign) LBReactBridgeMode mode;
//是否在主线程下载 & 加载
@property (nonatomic, assign) BOOL isBackground;

@property (nonatomic, assign) BOOL isEnterMainPage;

@property (nonatomic, copy) LBDownloadProgressBlock progress;

@property (nonatomic, copy) LBReactPatcherCompleteBlock complete;

/**
 将要或者当前渲染的patcher
 */
@property (nonatomic, strong) LBReactPatcherModel *renderPatcher;

@property (nonatomic, copy) LBReactBridgeJSCallbackBlock renderJSBlock;

@property (nonatomic, copy) LBReactBridgeJSCallbackBlock renderPageBlock;

@property (nonatomic, copy) void (^showUpdateAlertBlock)(UIViewController *controller) ;

@end

@implementation LBReactSinglePatcher

+ (instancetype)manager {
    static LBReactSinglePatcher *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[LBReactSinglePatcher alloc] init];
        //初始化将要渲染的
        LBReactPatcherDao *dao = [instance patcherDao];
        instance.renderPatcher = [instance validCachedPatcher:dao];
        [dao.database close];
    });
    return instance;
}

- (LBReactPatcherModel *)renderPatcher {
    return _renderPatcher;
}

- (void)start:(LBReactBridgeMode)mode
 isBackground:(BOOL)isBackground
launchOptions:(NSDictionary *)launchOptions
     response:(NSDictionary *)response
     progress:(LBDownloadProgressBlock)progress
     complete:(LBReactPatcherCompleteBlock)complete {
    
    self.mode = mode;
    self.isBackground = isBackground;
    self.launchOptions = launchOptions;
    self.progress = progress;
    self.complete = complete;
    self.showUpdateAlertBlock = nil;
    
    LBReactPatcherDao *dao = [self patcherDao];
    LBReactPatcherModel *patcher = [self validCachedPatcher:dao];
    
    //走下载流程
    //这里只需要下载给定的数据即可，失败就展示patcher，然后默认的
    if ([response isKindOfClass:[NSDictionary class]]) {
        [self response:nil
               success:response
               patcher:patcher
                   dao:dao];
    } else {
        //检查更新
        //下载最近一次未成功的，即该接口返回的，或者数据库中拿出的最近的一个未下载好的
        //备注：1.下载好的依据是可以找到本地中解压缩完
        //     2.根据接口返回更新当前的index
        if (mode != LBReactBridgeServerMode) {
            [self request:patcher
                      dao:dao];
        }
    }
}

- (void)appDidEnterMainPage:(UIViewController *)rootViewController {
    [self removeObserver];
    //前后台切换
    [self addObserver];
    LBBlockSafeRun(self.showUpdateAlertBlock, rootViewController);
    self.isEnterMainPage = YES;
}

- (void)registerJSCallback:(LBReactBridgeJSCallbackBlock)renderJSBlock
           renderPageBlock:(LBReactBridgeJSCallbackBlock)renderPageBlock {
    
    __weak __typeof(&*self) weakSelf = self;
    self.renderJSBlock = renderJSBlock;
    self.renderPageBlock = ^{
        LBBlockSafeRun(renderPageBlock);
    };
    
    //3.等待JS回调 关掉闪屏 加载主JS页面
    void (^callback)(void) = ^{
        LBBlockSafeRun(weakSelf.renderJSBlock);
    };
    void (^renderCallback)(void) = ^{
        LBBlockSafeRun(weakSelf.renderPageBlock);
    };
    [[LBReactBridge manager] registerJSCallback:callback];
    [[LBReactBridge manager] registerJSRenderCallback:renderCallback];
}

- (void)appDidEnterForeground:(NSNotification *)noti {
    //前后台切换的状态下，只认为加载本地的
    [self start:NO
   isBackground:YES
  launchOptions:nil
       response:nil
       progress:nil
       complete:nil];
}

- (void)request:(LBReactPatcherModel *)patcher
            dao:(LBReactPatcherDao *)dao {
    
    LBBaseRequest *baseRequest = [LBBaseRequest defaultRequest:@"0"];
    baseRequest.apiKey = [NSBundle stringValueWithConfigurationService:LBReactPatcherServiceConfiguration
                                                                   key:LBReactPatcherServiceInterfaceName
                                                          defaultValue:@"wisdom.system.app.queryNewApp"];;
    baseRequest.data = @{
                         @"patchType": @"react-native"
                         };
    NSDictionary *params = [baseRequest signRequest];
    
    NSString *host = [NSBundle stringValueWithConfigurationService:LBReactPatcherServiceConfiguration
                                                               key:LBReactPatcherServiceServerAddressName
                                                      defaultValue:@"https://proxy.zanfin.com"];
    NSString *URLString = [host stringByAppendingPathComponent:@"/api/proxy"];
    
    void(^success)(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) = ^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if ([responseObject isKindOfClass:[NSDictionary class]]) {
            [self response:task
                   success:responseObject
                   patcher:patcher
                       dao:dao];
        } else {
            [dao.database close];
        }
    };
    void(^failure)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) = ^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //关闭数据库
        [dao.database close];
    };
    
    [[LBHTTPSessionManager manager] POST:URLString
                              parameters:params
                                progress:nil
                                 success:success
                                 failure:failure];
}

- (void)response:(NSURLSessionDataTask *)task
         success:(NSDictionary *)responseObject
         patcher:(LBReactPatcherModel *)patcher
             dao:(LBReactPatcherDao *)dao {
    LBBaseResponse *response = [LBBaseResponse yy_modelWithJSON:responseObject];
    if ([response isBlushMarkSuccess]) {
        LBReactPatcherResponseModel *patcherResponse = [LBReactPatcherResponseModel yy_modelWithJSON:response.data];
        //下载
        if (patcherResponse.url.length > 0 && patcherResponse.bundleId > 0) {
            [self download:patcherResponse
                       dao:dao];
        } else {
            [dao.database close];
            if ([patcher isValidate]) {
                LBReactBridgeRenderState state = [LBReactBridge manager].renderState;
                if (!self.isBackground
                    || state == LBReactBridgeRenderStateUnKown
                    || state == LBReactBridgeRenderStateFail) {
                    [self render:patcher];
                } else {
                    LBBlockSafeRun(self.complete, YES);
                }
            } else {
                if (!self.isBackground) {
                    [self showInvalidateAlert:nil];
                }
                LBBlockSafeRun(self.complete, NO);
            }
        }
    } else {
        [dao.database close];
        LBBlockSafeRun(self.complete, NO);
    }
}

- (void)download:(LBReactPatcherModel *)patcher
             dao:(LBReactPatcherDao *)dao {
    void(^complete)(BOOL isSuccess, LBDownloaderModel *downloader) = ^(BOOL isSuccess, LBDownloaderModel *downloader) {
        //保存信息
        if (isSuccess) {
            //数据库存储均为已下载解压缩成功的数据
            //请求已经加类型限制，这里可以写死
            patcher.type = LBReactPatcherTypeReactNative;
            
            //展示弹框
            //重新render的不需要 launchOptions
            // TODO
            NSArray<LBReactPatcherModel *> *patchers = [dao selectByVersion:[LBDeviceUtil appVersion]
                                                                 identifier:[LBDeviceUtil bundleIdentifier]
                                                                mainVersion:@"0"
                                                                       type:LBReactPatcherTypeReactNative];
            [patchers enumerateObjectsUsingBlock:^(LBReactPatcherModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                obj.state = patcher.state;
                [dao updateState:obj];
            }];
            
            if (patchers.count > 0 || [dao insert:patcher]) {
                if (!self.isBackground) {
                    [self render:patcher];
                } else {
                    if (self.isEnterMainPage) {
                        [self showAlert:patcher controller:nil];
                    } else {
                        __weak __typeof(&*self) weakSelf = self;
                        self.showUpdateAlertBlock = ^(UIViewController *controller){
                            [weakSelf showAlert:patcher controller:controller];
                        };
                    }
                }
            } else {
                //保存失败的话
                LBBlockSafeRun(self.complete, NO);
            }
        } else {
            LBBlockSafeRun(self.complete, NO);
        }
        [dao.database close];
    };
    [[LBDownloader manager] start:patcher.url
                            unzip:YES
                            cache:NO
                         progress:self.progress
                         complete:complete];
}

- (void)showAlert:(LBReactPatcherModel *)patcher
       controller:(UIViewController *)controller {
    beginExecInMainBlock
    //确认后重新渲染
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"温馨提示"
                                                                             message:@"配置已更新，请重新加载"
                                                                      preferredStyle:UIAlertControllerStyleAlert];
    if (!patcher.isLaunchShow) {
        [alertController addAction:[UIAlertAction actionWithTitle:@"取消"
                                                            style:UIAlertActionStyleCancel
                                                          handler:^(UIAlertAction * _Nonnull action) {
                                                              LBBlockSafeRun(self.complete, YES);
                                                          }]];
    }
    
    void(^confirm)(UIAlertAction * _Nonnull action) = ^(UIAlertAction * _Nonnull action) {
        [self render:patcher];
    };
    UIAlertAction *action = [UIAlertAction actionWithTitle:@"更新"
                                                     style:UIAlertActionStyleDefault
                                                   handler:confirm];
    [alertController addAction:action];
    
    UIViewController *rootViewController = controller ? : [UIApplication displayViewController];
    [rootViewController  presentViewController:alertController
                                      animated:YES
                                    completion:nil];
    endExecInMainBlock
}

- (void)showInvalidateAlert:(UIViewController *)controller {
    beginExecInMainBlock
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"温馨提示"
                                                                             message:@"暂无可用版本，请稍后再试"
                                                                      preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:[UIAlertAction actionWithTitle:@"确定"
                                                        style:UIAlertActionStyleCancel
                                                      handler:nil]];
    UIViewController *rootViewController = controller ? : [UIApplication displayViewController];
    [rootViewController  presentViewController:alertController
                                      animated:YES
                                    completion:nil];
    endExecInMainBlock
}

- (void)render:(LBReactPatcherModel *)patcher {
    if ([patcher isValidate]) {
        //将要渲染该补丁包
        self.renderPatcher = patcher;
        
        void(^complete)(BOOL isSuccess, LBDownloaderModel *downloader) = ^(BOOL isSuccess, LBDownloaderModel *downloader){
            if (isSuccess) {
                void(^renderComplete)(BOOL isSuccess, NSError *error, BOOL isUpdate) = ^(BOOL isSuccess, NSError *error, BOOL isUpdate) {
                    LBBlockSafeRun(self.complete, isSuccess);
                };
                [[LBReactBridge manager] render:self.mode
                                     bundlePath:downloader.unzipFolderPath
                                  launchOptions:self.launchOptions
                                       complete:renderComplete];
            } else {
                //缓存读取失败，清除该条历史记录，避免下次启动脏数据影响
                LBReactPatcherDao *dao = [self patcherDao];
                [dao delete:patcher];
                [dao.database close];
                
                LBBlockSafeRun(self.complete, NO);
            }
        };
        //读取本地cache
        [[LBDownloader manager] start:patcher.url
                                unzip:YES
                                cache:YES
                             complete:complete];
    } else {
        if (!self.isBackground) {
            [self showInvalidateAlert:nil];
        }
        LBBlockSafeRun(self.complete, NO);
    }
}

- (void)renderDevelopment {
    [[LBReactBridge manager] render:LBReactBridgeServerMode
                         bundlePath:nil
                      launchOptions:self.launchOptions
                           complete:nil];
}

/**
 加载APP中自带bundle
 */
- (void)render {
    [self renderWithSourceName:@"page.resource"];
}

/**
 加载APP中自带bundle
 */
- (void)renderWithSourceName:(NSString *)name {
    
    //从本地取压缩好的默认包，文件名包括版本号
    NSString *bundleFolderName = [NSString stringWithFormat:@"%@-%@-%@",
                                  name,
                                  AppReleaseVersionNumber()?:@"0.0.0",
                                  AppBuildVersionNumber()?:@"0"];
    NSString *defaultBundleName = [NSString stringWithFormat:@"%@.bundle", name];
    NSString *bundleFolderPath = [LBPathDocument stringByAppendingPathComponent:bundleFolderName];
    NSString *defaultBundlePath = [bundleFolderPath stringByAppendingPathComponent:defaultBundleName];
    
    NSError *error;
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:bundleFolderPath]) {
        [fileManager createDirectoryAtPath:bundleFolderPath
               withIntermediateDirectories:YES
                                attributes:nil
                                     error:&error];
    }
    
    if (error) {
        return;
    }
    
    if ([fileManager fileExistsAtPath:defaultBundlePath]) {
        [[LBReactBridge manager] render:self.mode
                             bundlePath:bundleFolderPath
                          launchOptions:self.launchOptions
                               complete:nil];
    } else {
        
        //解密
        NSString *contents = [[NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:name withExtension:@"bundle"]] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        
        NSString *script = contents;
        //TODO JS AES
//        NSString *script = [LBAES decryptAES:contents
//                                         key:@"274FBAFFA7174BE7EFBD4A81227CE358"
//                               initialVector:@"5EA5408669D88CB9B203749AE1348248"
//                                     keySize:kWLKeySizeAES128];
        if (script){
            [script writeToFile:defaultBundlePath
                     atomically:YES
                       encoding:NSUTF8StringEncoding
                          error:&error];
            if (error == nil) {
                //拷贝资源
                NSString *assetsPath = [bundleFolderPath stringByAppendingPathComponent:@"assets"];
                [fileManager copyItemAtPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"assets" ]
                                     toPath:assetsPath
                                      error:&error];
                
                if (error == nil) {
                    [[LBReactBridge manager] render:self.mode
                                         bundlePath:bundleFolderPath
                                      launchOptions:self.launchOptions
                                           complete:nil];
                } else {
                    [fileManager removeItemAtPath:defaultBundlePath error:nil];
                    [fileManager removeItemAtPath:assetsPath error:nil];
                }
            } else {
                [fileManager removeItemAtPath:defaultBundlePath error:nil];
            }
        }
    }
}

#pragma mark - Getter
- (LBReactPatcherDao *)patcherDao {
    //初始化数据库对象
    LBDatabase *db = [LBDatabase database:@"patcher.db"];
    LBReactPatcherDao *dao = [[LBReactPatcherDao alloc] initWithDatabase:db];
    
    return dao;
}

- (LBReactPatcherModel *)validCachedPatcher:(LBReactPatcherDao *)dao {
    //加载本地
    NSArray<LBReactPatcherModel *> *patchers = [dao selectByVersion:[LBDeviceUtil appVersion]
                                                         identifier:[LBDeviceUtil bundleIdentifier]
                                                        mainVersion:nil
                                                               type:LBReactPatcherTypeReactNative];
    LBReactPatcherModel *patcher = patchers.lastObject;
    //这里为了与安卓统一，如果最近一次的补丁包失效，则使用原始补丁包
    if ([patcher isValidate]) {
        return patcher;
    }
    return nil;
}

#pragma mark - Private Mthod
- (void)addObserver {
//    [[NSNotificationCenter defaultCenter] addObserver:self
//                                             selector:@selector(appDidEnterForeground:)
//                                                 name:UIApplicationWillEnterForegroundNotification
//                                               object:nil];
}

- (void)removeObserver {
//    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
